%include "conf.inc"
%include "pm.inc"
%include "desc.inc"

;;;  此处减 2 是为了增加头部两个字节
	org	OffsetOfLoader - 2
loader_len:		dw	0
	jmp	start
	
	[SECTION .s16]
	[BITS 16]
start:
	mov	si, EnterProtectedMode
	call	__puts

	;; 为什麽
	;; 对于代码段初始化需要使用 cs 的值
	;; 而对于数据段的则必须直接使用地址
	InitDescriptor LABEL_SEG_RING3, LABEL_DESC_RING3
	InitDescriptor LABEL_SEG_CODE32, LABEL_DESC_CODE32
	InitDescriptor LABEL_SEG_DATA, LABEL_DESC_DATA
	InitDescriptor LABEL_SEG_STACK0, LABEL_DESC_STACK0
	InitDescriptor LABEL_SEG_STACK3, LABEL_DESC_STACK3
	InitDescriptor LABEL_SEG_TSS, LABEL_DESC_TSS
	InitDescriptor LABEL_SEG_DEST, LABEL_DESC_DEST

	xor	eax, eax
	mov	ax, ds
	shl	eax, 4
	add	eax, LABEL_GDT
	mov	dword [GdtPtr + 2], eax

	lgdt	[GdtPtr]

	cli
	in	al, 92h
	or	al, 00000010b
	out	92h, al

	mov	eax, cr0
	or	eax, 0x1
	mov	cr0, eax

	jmp	dword SelectorCode32:0

	
	;;  ---------------------------------
	;;  打印字符串
	;;  ---------------------------------
__puts:
	pusha
	mov	ah, 0x0e
	xor	bh, bh
	.loop:
	lodsb
	test	al, al
	jz	.done
	int	0x10
	jmp	.loop
	.done:
	popa
	ret

EnterProtectedMode:		db	'This is loader..', 13, 10, 0
	
	[SECTION	.gdt]
	[BITS	32]
LABEL_GDT:		Descriptor	0, 	0,	0
LABEL_DESC_CODE32:	Descriptor	0, 	SegCode32Len - 1, DA_C + DA_32
LABEL_DESC_DEST:	Descriptor	0, 	SegDestLen - 1, DA_C + DA_32
LABEL_DESC_VIDEO:	Descriptor	0B8000h,0ffffh, DA_DRW
LABEL_DESC_STACK0:	Descriptor	0, 	TopOfStack0, DA_DRWA + DA_32
LABEL_DESC_DATA:	Descriptor	0, 	DataLen	- 1, DA_DRW
LABEL_DESC_RING3:	Descriptor	0, 	SegRing3Len - 1,  DA_C + DA_32
LABEL_DESC_STACK3:	Descriptor	0, 	TopOfStack3, DA_DRWA + DA_32
LABEL_DESC_TSS:		Descriptor	0, 	TssLen - 1, DA_386TSS
LABEL_CALL_GATE:	Gate	SelectorDest, 0, 0, DA_386CGate + DA_DPL0

	GdtLen		equ	$ - LABEL_GDT
	GdtPtr		dw	GdtLen	- 1
		dd	0

	SelectorCode32	equ	LABEL_DESC_CODE32	-	LABEL_GDT
	SelectorStack0	equ	LABEL_DESC_STACK0	- 	LABEL_GDT
	SelectorData	equ	LABEL_DESC_DATA		-	LABEL_GDT
	SelectorVideo	equ	LABEL_DESC_VIDEO	-	LABEL_GDT
	SelectorRing3	equ	LABEL_DESC_RING3	-	LABEL_GDT
	SelectorTss	equ	LABEL_DESC_TSS		-	LABEL_GDT
	SelectorStack3	equ	LABEL_DESC_STACK3	- 	LABEL_GDT
	SelectorDest	equ	LABEL_DESC_DEST		-	LABEL_GDT
	SelectorGate	equ	LABEL_CALL_GATE		-	LABEL_GDT

	[SECTION	.ring0]
	[BITS	32]
LABEL_SEG_CODE32:
	mov	ax, SelectorVideo
	mov	gs, ax
	mov	ax, SelectorData
	mov	ds, ax
	mov	ax, SelectorStack0
	mov	ss, ax
	mov	esp, TopOfStack0

	mov	ah, 0Ch
	xor	esi, esi
	xor	edi, edi
	mov	edi, (80 * 21 + 0) * 2
	mov	esi, MessageOffset
	mov	ecx, 10h
	.1:
	lodsb
	mov	[gs:edi], ax
	add	edi, 2
	loop	.1

	;; 
	mov	ax, SelectorTss
	ltr	ax
	push	SelectorStack3
	push	TopOfStack3
	push	SelectorRing3
	push	0

	
	retf
	
	SegCode32Len	equ	$ - LABEL_SEG_CODE32

	[SECTION .data]
	[BITS	32]
LABEL_SEG_DATA:
	SPValueInRealModel	dw	0
Message:		db	"In Proected Model.", 0
MessageOffset:		equ	Message	- $$
StrTest:		db	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
StrTestOffset:		equ	StrTest	- $$
	DataLen	equ	$ - LABEL_SEG_DATA

	[SECTION .ring3]
	[BITS 32]
LABEL_SEG_RING3:
	mov	ax, SelectorVideo
	mov	gs, ax

	mov	edi, (80 * 20 + 0) * 2
	mov	ah, 0Ch
	mov	al, '3'
	mov	[gs:edi], ax

	call 	SelectorGate:0
	
	jmp	$
	SegRing3Len	equ	$ - LABEL_SEG_RING3

	[SECTION .dest]
	[BITS	32]
LABEL_SEG_DEST:
	mov	ax, SelectorVideo
	mov	gs, ax

	mov	edi, (80 * 22 + 0) * 2
	mov	ah, 0Ch
	mov	al, 'C'
	mov	[gs:edi], ax

	retf
SegDestLen	equ	$ - LABEL_SEG_DEST

;;;  -------------------------------------
;;;
;;;  -------------------------------------
	
LABEL_SEG_TSS:
	DD	0		; Back
	DD	TopOfStack0	; ring 0 stack
	DD	SelectorStack0
	DD	0		; ring 1 stack
	DD	0
	DD	0		; ring 2 stack
	DD	0
	DD	0		; cr3
	DD	0		; eip
	DD	0		; eflags
	DD	0		; eax
	DD	0		; ecx
	DD	0		; edx
	DD	0		; ebx
	DD	0		; esp
	DD	0		; ebp
	DD	0		; esi
	DD	0		; edi
	DD	0		; es
	DD	0		; cs
	DD	0		; ss
	DD	0		; ds
	DD	0		; fs
	DD	0		; gs
	DD	0		; ldt
	DW	0		; trap
	DW	$ - LABEL_SEG_TSS + 2
	DB	0ffh		; IO bitmap 结束位
	TssLen	equ	$ - LABEL_SEG_TSS

;; -------------------------------------
;;  stack ring 0
;; -------------------------------------
	
LABEL_SEG_STACK0:
	times	64	db	0
	TopOfStack0	equ	$ - LABEL_SEG_STACK0 - 1

;; -------------------------------------
;;  stack ring 3
;; -------------------------------------
	
LABEL_SEG_STACK3:
	times	64	db	0
	TopOfStack3	equ	$ - LABEL_SEG_STACK3 - 1